﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Xml.XPath;
using System.Xml;
using System.ComponentModel;

namespace Microsoft.Mtool.FSM
{
    [Serializable]
    public enum ActionType
    {
        Control
    }

    [Serializable]
    public enum ActionSource
    {
        Token
    }

    [Serializable]
    public class Action
    {
        private string id;
        private ActionType type;
        private ActionSource source;
        private string from;
        private string to;
        private List<ActionImpl> stubs = new List<ActionImpl>();

        [XmlAttribute]
        public string Id
        {
            get { return id; }
            set { id = value; }
        }

        [XmlAttribute]
        public ActionType Type
        {
            get { return type; }
            set { type = value; }
        }

        [XmlAttribute]
        public ActionSource Source
        {
            get { return source; }
            set { source = value; }
        }

        [ReadOnly(true)]
        [XmlAttribute]
        public string From
        {
            get { return head == null ? from : head.Id; }
            set { from = value; }
        }

        [ReadOnly(true)]
        [XmlAttribute]
        public string To
        {
            get { return tail == null ? to : tail.Id; }
            set { to = value; }
        }

        [XmlArray]
        [XmlArrayItem(Type=typeof(TokenImpl)), XmlArrayItem(Type=typeof(FunctionImpl))]
        public List<ActionImpl> Stubs
        {
            get { return stubs; }
            set { stubs = value; }
        }

        [XmlIgnore]
        public bool IsEmpty
        {
            get { return stubs.Count == 0; }
        }

        private State head;
        private State tail;

        public Action()
        { }

        [Browsable(false)]
        [XmlIgnore]
        public State FromState
        {
            get { return head; }
            set { head = value; }
        }

        [Browsable(false)]
        [XmlIgnore]
        public State ToState
        {
            get { return tail; }
            set { tail = value; }
        }

        public Action(string id, ActionType type, ActionSource source, string from, string to)
        {
            this.id = id;
            this.type = type;
            this.source = source;
            this.from = from;
            this.to = to;
        }

        public Action(string id, ActionType type, ActionSource source, State from, State to)
            : this(id, type, source, from.Id, to.Id)
        {
            head = from;
            tail = to;
        }

        public void AddToken(TokenImpl impl)
        {   
            // keep the definition clear
            stubs.Add(impl.GetCopy());
        }

        public void AddFunc(FunctionImpl impl)
        {
            // keep the definition clear
            stubs.Add(impl.GetCopy());
        }

        public void RemoveActionImpl(ActionImpl token)
        {
            if (!stubs.Contains(token))
            {
                Logger.Instance.Warn("RemoveToken called, but the token to remove ({0}) doesnot exist!", token.Name);
                return;
            }
            stubs.Remove(token);
        }

        public void RemoveActionImplAt(int index)
        {
            if (index < 0 || index >= stubs.Count)
            {
                Logger.Instance.Warn("RemoveTokenAt called, but the token to remove (pos:{0}) doesnot exist!", index);
                return;
            }
            stubs.RemoveAt(index);
        }

        public void MoveUp(int index)
        {
            if (index <= 0 || index >= stubs.Count)
            {
                Logger.Instance.Warn("Unexpected input from UI to Action.Moveup with index = {0}", index);
            }
            ActionImpl tmp = stubs[index];
            stubs[index] = stubs[index - 1];
            stubs[index - 1] = tmp;
        }

        public void GenDefaults()
        {
            foreach (ActionImpl stub in stubs)
            {
                stub.GenDefaults();
            }
        }
    }
}
